#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define N 16 //用户名最大长度
#define R 1  //注册
#define L 2  //登录
#define Q 3  //查询
#define H 4  //查询历史记录

typedef struct{
    int type;
    char name[N];
    char data[256];
}MSG;

//注册处理函数
void handle_register(int sockfd, MSG *msg){
    msg->type = R;
    
    printf("请输入用户名:");
    scanf("%s", msg->name);
    printf("请输入密码:");
    scanf("%s", msg->data);

    //发送注册请求
    send(sockfd, msg, sizeof(MSG), 0);

    //接收响应
    recv(sockfd, msg, sizeof(MSG), 0);
    printf("注册:%s\n", msg->data);
}

//登录处理函数
int handle_login(int sockfd, MSG *msg){
    //设置消息类型为登录
    msg->type = L;

    printf("请输入用户名:");
    scanf("%s", msg->name);
    printf("请输入密码:");
    scanf("%s", msg->data);

    //发送登录请求
    send(sockfd, msg, sizeof(MSG), 0);

    //接收响应
    recv(sockfd, msg, sizeof(MSG), 0);
    
    if(strncmp(msg->data, "OK", 3) == 0){
        printf("登录成功!\n");
        return 1;
    }

    printf("登录失败:%s\n", msg->data);
    return 0;
}

//查询单词函数
void handle_query(int sockfd, MSG *msg){
    msg->type = Q;

    puts("----------------------");
    while(1){
        printf("请输入要查询的单词(输入#退出)\n");
        scanf("%s", msg->data);

        //退出条件
        if(strcmp(msg->data, "#") == 0){
            break;
        }

        send(sockfd, msg, sizeof(MSG), 0);

        recv(sockfd, msg, sizeof(MSG), 0);

        printf(">>> %s\n", msg->data);
    }
}

//查询历史记录函数
void handle_history(int sockfd, MSG *msg){
    msg->type = H;

    //发送查询历史请求
    send(sockfd, msg, sizeof(MSG), 0);

    //循环接收历史记录
    while(1){
        recv(sockfd, msg, sizeof(MSG), 0);

        //结束标记检查 **OVER**
        if(strcmp(msg->data, "**OVER**") == 0){
            break;
        }

        printf("%s\n", msg->data);
    }
}

//功能菜单
void query_menu(int sockfd, MSG *msg){
    int choose = 0;
    while(1){

        //打印功能菜单
        printf("*******************************\n");
        printf("1.查询单词\n");
        printf("2.查询历史记录\n");
        printf("3.退出\n");
        printf("*******************************\n");
        printf("请输入功能菜单功能:(1|2|3)\n");

        if(scanf("%d", &choose) <= 0){
            perror("接收输入失败");
            return;
        }

        switch (choose){
        case 1://查询单词
            //调用查询单词函数
            handle_query(sockfd, msg);
            break;
        case 2://查询历史记录
            //调用查询历史记录函数
            handle_history(sockfd, msg);
            break;
        case 3://退出
            close(sockfd);
            exit(0);
        default :
            break;
        }
    }
}

int main(int argc, char *argv[]){
    //参数检查
    if(argc < 3){
        printf("格式:%s <服务ip> <服务端口>\n", argv[0]);
        return -1;
    }

    //创建TCP套接字
    int sockfd;
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        perror("socket创建失败\n");
        return -1;
    }

    struct sockaddr_in server_addr;

    //清空结构体
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);

    if(connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){
        perror("connect失败\n");
        close(sockfd);
        return -1;
    }

    int choose;
    MSG msg;

    while(1){
        //打印主菜单
        printf("*******************************\n");
        printf("1.注册\n");
        printf("2.登录\n");
        printf("3.退出\n");
        printf("*******************************\n");
        printf("请输入主菜单功能:(1|2|3)\n");

        //获取用户输入
        if(scanf("%d", &choose) <= 0){
            printf("输入错误\n");
            return -1;
        }

        switch (choose){
        case 1://注册
            //调用处理注册函数
            handle_register(sockfd, &msg);
            break;
        case 2://登录
            //调用处理登录函数
            if(handle_login(sockfd, &msg) == 1){
                //调用跳转功能菜单页面
                query_menu(sockfd, &msg);
            }
            break;
        case 3://退出
            close(sockfd);
            return 0;
        }
    }

    return 0;
}